﻿using KinonekoSoftware.Studio.Collections;

namespace KinonekoSoftware.Studio.Pages.Shenanigans
{
    /// <summary>
    /// <see cref="CharacterDataSource"/> 类型表示一个抽象，用于提炼出所有关于 <see cref="Character"/>操作的通用代码。
    /// </summary>
    public sealed partial class CharacterDataSource
    {
        private static readonly ObservableCollection<Character>      GlobalCollection;
        private static readonly ObservableCollection<Character>      DebugOnly;
        private static readonly DictionaryAdapter<string, Character> GlobalIDMap;

        private static TalkingEngine       TalkingEngineInternal;
        private static InstanceCacheEngine InstanceEngineInternal;
        private static string              Bundle;

        private readonly DictionaryAdapter<string, Character> ScopedIDMap;
        private readonly ObservableCollection<Character>      ScopedCollection;

        static CharacterDataSource()
        {
            GlobalCollection = new ObservableCollection<Character>();
            DebugOnly        = new ObservableCollection<Character>();
            GlobalIDMap      = new DictionaryAdapter<string, Character>();

            for (var i = 0; i < 24; i++)
            {
                DebugOnly.Add(new Character
                {
                    Id     = ID.Get(),
                    Name   = $"Character No.0{i + 1}",
                });
            }
        }

        public CharacterDataSource()
        {
            ScopedIDMap      = new DictionaryAdapter<string, Character>();
            ScopedCollection = new ObservableCollection<Character>();
        }

        #region Global Scoped

        /// <summary>
        /// 添加并缓存Character，此操作仅限于全局Character集合。
        /// </summary>
        /// <param name="character"></param>
        /// <param name="loading"></param>
        public static void AddOrCache(Character character, bool loading = true)
        {
            if (character is null)
            {
                return;
            }

            if (GlobalIDMap.TryAdd(character.Id, character))
            {
                if (!loading)
                {
                    //
                    //
                    TalkingEngine.AddCharacter(character);
                }

                //
                //
                GlobalCollection.Add(character);
            }
        }

        /// <summary>
        /// 更新所有Character，此操作仅限于全局Character集合。
        /// </summary>
        public static void Update()
        {
            foreach (var character in GlobalCollection)
            {
                var maybeExistsCharater = InstanceEngine.Get(character.Id);

                if (maybeExistsCharater is null)
                {
                    continue;
                }

                character.Avatar = maybeExistsCharater.Avatar;
                character.Name   = maybeExistsCharater.Name;
            }
        }

        /// <summary>
        /// 加载所有Character，此操作仅限于全局Character集合。
        /// </summary>
        public static void Initialize()
        {
            if (!string.IsNullOrEmpty(Bundle))
            {
                if (Bundle != Platform.RepositoryHashCode)
                {
                    Clear();
                }
                else
                {
                    return;
                }
            }

            //
            //
            Bundle = Platform.RepositoryHashCode;

            //
            //
            var characters = TalkingEngine.GetCharacters();

            //
            //
            foreach (var character in characters)
            {
                AddOrCache(character);
            }
            
        }

        /// <summary>
        /// 清除所有Character，此操作仅限于全局Character集合。
        /// </summary>
        public static void Clear()
        {
            GlobalCollection.Clear();
            GlobalIDMap.Clear();
        }

        /// <summary>
        /// 移除Character，此操作仅限于全局Character集合。
        /// </summary>
        public static void Remove(Character character)
        {
            //
            //
            GlobalIDMap.Remove(character.Id);
            TalkingEngine.RemoveCharacter(character);
            GlobalCollection.Remove(character);
        }

        public static Character Get(string id) => GlobalIDMap.GetValueOrDefault(id);
        
        #endregion

        #region Transient Scoped

        public void Initialize(Character owner)
        {
            //
            //
            ScopedAdd(owner);
        }

        public void Initialize(IEnumerable<Character> characters)
        {
            foreach (var character in characters)
            {
                //
                //
                ScopedAdd(character);
            }
        }

        public void ScopedAdd(Character character)
        {
            if (ScopedIDMap.TryAdd(character.Id, character))
            {
                TransientScopedCollection.Add(character);
            }
        }
        
        
        public void ScopedUpdate()
        {
            foreach (var character in ScopedCollection)
            {
                var maybeExistsCharater = InstanceEngine.Get(character.Id);

                if (maybeExistsCharater is null)
                {
                    continue;
                }

                character.Avatar = maybeExistsCharater.Avatar;
                character.Name   = maybeExistsCharater.Name;
            }
        }

        public void ScopedClear()
        {
            ScopedIDMap.Clear();
            ScopedCollection.Clear();
        }

        
        /// <summary>
        /// 移除Character，此操作仅限于全局Character集合。
        /// </summary>
        public void ScopedRemove(Character character)
        {
            //
            //
            GlobalIDMap.Remove(character.Id);
            TalkingEngine.RemoveCharacter(character);
            GlobalCollection.Remove(character);
        }
        
        
        public Character ScopedGet(string id)
        {
            if(id == CharacterEngine.Character_AuthorID)
            {
                return GlobalIDMap.GetValueOrDefault(id);
            }

            return ScopedIDMap.GetValueOrDefault(id);
        }
        #endregion



        public bool                                 HasItemInTransientScoped  => ScopedCollection.Count > 0;
        public ObservableCollection<Character>      TransientScopedCollection => ScopedCollection;
        public DictionaryAdapter<string, Character> TransientScopedDictionary => ScopedIDMap;

        public static bool                                 HasItemInGlobalScoped  => GlobalCollection.Count > 0;
        public static ObservableCollection<Character>      GlobalScopedCollection => GlobalCollection;
        public static ObservableCollection<Character>      DebugOnlyCollection    => DebugOnly;
        public static DictionaryAdapter<string, Character> GlobalScopedDictionary => GlobalIDMap;

        public static TalkingEngine       TalkingEngine  => TalkingEngineInternal ??= Platform.GetEngine<TalkingEngine>();
        public static InstanceCacheEngine InstanceEngine => InstanceEngineInternal ??= Platform.GetEngine<InstanceCacheEngine>();

    }
}